package com.zhangsun.multiAop.framework.aop;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import com.zhangsun.multiAop.framework.Enums.DBTypeEnum;
import com.zhangsun.multiAop.framework.db.DbContextHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Type;

@Component
@Aspect
@Order(-100) //这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高
public class DataSourceSwitchAspect {

    private static final String DB1_PACKAGE = "com.zhangsun.db1";

    private static final String DB2_PACKAGE = "com.zhangsun.db2";

    @Pointcut("execution(* com.zhangsun.*.mapper..*.*(..))")
    private void dbType() {
    }

    @Before("dbType()")
    public void before(JoinPoint joinPoint) {
        Type[] types = AopUtils.getTargetClass(joinPoint.getTarget()).getGenericInterfaces();
        Package dbPackage = ((Class) types[0]).getPackage();
        if (StrUtil.startWith(dbPackage.getName(), DB1_PACKAGE)) {
            switchDB(DBTypeEnum.DB1);
        } else if (StrUtil.startWith(dbPackage.getName(), DB2_PACKAGE)) {
            switchDB(DBTypeEnum.DB2);
        }
    }

    /**
     * 切换数据源
     *
     * @param dbType 数据库
     */
    private void switchDB(DBTypeEnum dbType) {
        StaticLog.info("switch data sources : " + dbType.getValue());
        DbContextHolder.setDbType(dbType);
    }

    @After("dbType()")
    public void after() {
        String db = DbContextHolder.getDbType();
        if (StrUtil.isNotBlank(db)) {
            StaticLog.info("Revert DataSource : " + db);
            // 方法执行完毕之后，销毁当前数据源信息，进行垃圾回收。
            DbContextHolder.clearDbType();
        }
    }

}
